#ifndef __OCPP_Cesium_HeadingPitchRoll_H__
#define __OCPP_Cesium_HeadingPitchRoll_H__

#include "CesiumMath.h"

namespace OCPP
{
	namespace Cesium
	{

		class _CesiumExport HeadingPitchRoll
		{
		public:
			double heading, pitch, roll;
			HeadingPitchRoll(double _x = 0.0, double _y = 0.0, double _z = 0.0)
				: heading(_x)
				, pitch(_y)
				, roll(_z)
			{

			}

			HeadingPitchRoll(const HeadingPitchRoll& other)
			{
				this->heading = other.heading;
				this->pitch = other.pitch;
				this->roll = other.roll;
			}

			HeadingPitchRoll& operator = (const HeadingPitchRoll& other)
			{
				this->heading = other.heading;
				this->pitch = other.pitch;
				this->roll = other.roll;

				return (HeadingPitchRoll&)*this;
			}

			/**
			 * Computes the heading, pitch and roll from a quaternion (see http://en.wikipedia.org/wiki/Conversion_between_quaternions_and_Euler_angles )
			 *
			 * @param {Quaternion} quaternion The quaternion from which to retrieve heading, pitch, and roll, all expressed in radians.
			 * @param {HeadingPitchRoll} [result] The object in which to store the result. If not provided, a new instance is created and returned.
			 * @returns {HeadingPitchRoll} The modified result parameter or a new HeadingPitchRoll instance if one was not provided.
			 */
			static HeadingPitchRoll  fromQuaternion(Quaternion quaternion);;

			/**
			 * Returns a new HeadingPitchRoll instance from angles given in degrees.
			 *
			 * @param {number} heading the heading in degrees
			 * @param {number} pitch the pitch in degrees
			 * @param {number} roll the heading in degrees
			 * @param {HeadingPitchRoll} [result] The object in which to store the result. If not provided, a new instance is created and returned.
			 * @returns {HeadingPitchRoll} A new HeadingPitchRoll instance
			 */
			static HeadingPitchRoll fromDegrees(double heading, double pitch, double roll) {
				HeadingPitchRoll result;
				result.heading = heading * CesiumMath::RADIANS_PER_DEGREE;
				result.pitch = pitch * CesiumMath::RADIANS_PER_DEGREE;
				result.roll = roll * CesiumMath::RADIANS_PER_DEGREE;
				return result;
			};

			/**
			 * Compares the provided cartographics componentwise and returns
			 * <code>true</code> if they are equal, <code>false</code> otherwise.
			 *
			 * @param {HeadingPitchRoll} [left] The first cartographic.
			 * @param {HeadingPitchRoll} [right] The second cartographic.
			 * @returns {boolean} <code>true</code> if left and right are equal, <code>false</code> otherwise.
			 */
			static bool equals(HeadingPitchRoll left, HeadingPitchRoll right) {
				return (
					left.heading == right.heading &&
					left.pitch == right.pitch &&
					left.roll == right.roll
					);
			}

			/**
			 * Compares the provided cartographics componentwise and returns
			 * <code>true</code> if they are within the provided epsilon,
			 * <code>false</code> otherwise.
			 *
			 * @param {HeadingPitchRoll} [left] The first
			 * @param {HeadingPitchRoll} [right] The second
			 * @param {number} [epsilon=0] The epsilon to use for equality testing.
			 * @returns {boolean} <code>true</code> if left and right are within the provided epsilon, <code>false</code> otherwise.
			 */
			static bool equalsEpsilon(HeadingPitchRoll left, HeadingPitchRoll right,
				double relativeEpsilon = 0.0,
				double absoluteEpsilon = 0.0) {
				return (
						CesiumMath::equalsEpsilon(
							left.heading,
							right.heading,
							relativeEpsilon,
							absoluteEpsilon
						) &&
						CesiumMath::equalsEpsilon(
							left.pitch,
							right.pitch,
							relativeEpsilon,
							absoluteEpsilon
						) &&
						CesiumMath::equalsEpsilon(
							left.roll,
							right.roll,
							relativeEpsilon,
							absoluteEpsilon
						)
					);
			};

			/**
			 * Compares the provided against this cartographic componentwise and returns
			 * <code>true</code> if they are equal, <code>false</code> otherwise.
			 *
			 * @param {HeadingPitchRoll} [right] The second cartographic.
			 * @returns {boolean} <code>true</code> if left and right are equal, <code>false</code> otherwise.
			 */
			bool equals(HeadingPitchRoll right) {
				return HeadingPitchRoll::equals(*this, right);
			};

			/**
			 * Compares the provided against this cartographic componentwise and returns
			 * <code>true</code> if they are within the provided epsilon,
			 * <code>false</code> otherwise.
			 *
			 * @param {HeadingPitchRoll} [right] The second cartographic.
			 * @param {number} [epsilon=0] The epsilon to use for equality testing.
			 * @returns {boolean} <code>true</code> if left and right are within the provided epsilon, <code>false</code> otherwise.
			 */
			bool equalsEpsilon(HeadingPitchRoll right, double epsilon = 0.0) {
				return HeadingPitchRoll::equalsEpsilon(*this, right, epsilon);
			};

			/**
			 * Creates a string representing this cartographic in the format '(longitude, latitude, height)'.
			 *
			 * @returns {string} A string representing the provided cartographic in the format '(longitude, latitude, height)'.
			 */
			String toString() {
				return str_format("%f,%f,%f,%f", heading, pitch, roll);
			};
		};

	}
}

#endif

